From eb837a4888ab4e0fa91931f49a927e7af0254367 Mon Sep 17 00:00:00 2001
From: Jeremy Rand <jeremyrand@airmail.cc>
Date: Tue, 4 Aug 2020 02:42:00 +0000
Subject: [PATCH 1/2] Launch Namecoin on Linux

---
 src/components/tl-process.js | 60 ++++++++++++++++++++++++++++++++++--
 src/modules/tl-util.jsm      |  8 +++++
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index e9d7cde..510cbaf 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -393,11 +393,30 @@ TorProcessService.prototype =
       var torrcFile = TorLauncherUtil.getTorFile("torrc", true);
       var torrcDefaultsFile =
                     TorLauncherUtil.getTorFile("torrc-defaults", false);
+      var electrumNMCFile = null;
+      var stemNSFile = null;
       var hashedPassword = this.mProtocolSvc.TorGetPassword(true);
       var controlIPCFile = this.mProtocolSvc.TorGetControlIPCFile();
       var controlPort = this.mProtocolSvc.TorGetControlPort();
       var socksPortInfo = this.mProtocolSvc.TorGetSOCKSPortInfo();
 
+      let env = Cc["@mozilla.org/process/environment;1"]
+                  .getService(Ci.nsIEnvironment);
+
+      var enableNamecoin = false;
+      if (env.exists("TOR_ENABLE_NAMECOIN"))
+        enableNamecoin = env.get("TOR_ENABLE_NAMECOIN") == "1";
+
+      var verboseNamecoin = false;
+      if (enableNamecoin)
+      {
+        if (env.exists("TOR_VERBOSE_NAMECOIN"))
+          verboseNamecoin = env.get("TOR_VERBOSE_NAMECOIN") == "1";
+
+        electrumNMCFile = TorLauncherUtil.getTorFile("electrum-nmc", false);
+        stemNSFile = TorLauncherUtil.getTorFile("stemns", false);
+      }
+
       var detailsKey;
       if (!exeFile)
         detailsKey = "tor_missing";
@@ -407,11 +426,16 @@ TorProcessService.prototype =
         detailsKey = "datadir_missing";
       else if (!onionAuthDir)
         detailsKey = "onionauthdir_missing";
+      else if (!electrumNMCFile && enableNamecoin)
+        detailsKey = "electrum_nmc_missing";
+      else if (!stemNSFile && enableNamecoin)
+        detailsKey = "stemns_missing";
       else if (!hashedPassword)
         detailsKey = "password_hash_missing";
 
       if (detailsKey)
       {
+        // TODO: add strings for Electrum-NMC and StemNS
         var details = TorLauncherUtil.getLocalizedString(detailsKey);
         var key = "unable_to_start_tor";
         var err = TorLauncherUtil.getFormattedLocalizedString(key,
@@ -517,11 +541,15 @@ TorProcessService.prototype =
         args.push("1");
       }
 
+      if (enableNamecoin)
+      {
+        args.push("__LeaveStreamsUnattached");
+        args.push("1");
+      }
+
       // Set an environment variable that points to the Tor data directory.
       // This is used by meek-client-torbrowser to find the location for
       // the meek browser profile.
-      let env = Cc["@mozilla.org/process/environment;1"]
-                  .getService(Ci.nsIEnvironment);
       env.set("TOR_BROWSER_TOR_DATA_DIR", dataDir.path);
 
       // On Windows, prepend the Tor program directory to PATH.  This is
@@ -547,6 +575,34 @@ TorProcessService.prototype =
       p.runwAsync(args, args.length, this, false);
       this.mTorProcess = p;
       this.mTorProcessStartTime = Date.now();
+
+      if (enableNamecoin)
+      {
+        args = [];
+        args.push("daemon");
+        if (verboseNamecoin)
+          args.push("-v");
+        args.push("--dir");
+        args.push("TorBrowser/Data/Electrum-NMC/");
+
+        p = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+        p.init(electrumNMCFile);
+
+        TorLauncherLogger.log(2, "Starting " + electrumNMCFile.path);
+        for (var i = 0; i < args.length; ++i)
+          TorLauncherLogger.log(2, "  " + args[i]);
+
+        p.runwAsync(args, args.length, this, false);
+
+        args = [];
+
+        p = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+        p.init(stemNSFile);
+
+        TorLauncherLogger.log(2, "Starting " + stemNSFile.path);
+
+        p.runwAsync(args, args.length, this, false);
+      }
     }
     catch (e)
     {
diff --git a/src/modules/tl-util.jsm b/src/modules/tl-util.jsm
index b721372..ad56752 100644
--- a/src/modules/tl-util.jsm
+++ b/src/modules/tl-util.jsm
@@ -613,6 +613,10 @@ let TorLauncherUtil =  // Public
             path = "Tor/PluggableTransports";
           else if (isIPC)
             path = "Tor/" + ipcFileName;
+          else if ("electrum-nmc" == aTorFileType)
+            path = "TorBrowser/Electrum-NMC/run_electrum_nmc";
+          else if ("stemns" == aTorFileType)
+            path = "TorBrowser/StemNS/poc.py";
         }
       }
       else if (this.isWindows)
@@ -652,6 +656,10 @@ let TorLauncherUtil =  // Public
           path = "Data/Browser";
         else if (isIPC)
           path = "Data/Tor/" + ipcFileName;
+        else if ("electrum-nmc" == aTorFileType)
+          path = "Electrum-NMC/run_electrum_nmc";
+        else if ("stemns" == aTorFileType)
+          path = "StemNS/poc.py";
       }
 
       if (!path && !useAppDir)
-- 
2.20.1


From b65d5e8b5256d2f6ae41f248dc95048d43336c43 Mon Sep 17 00:00:00 2001
From: Jeremy Rand <jeremyrand@airmail.cc>
Date: Wed, 19 Aug 2020 05:19:19 +0000
Subject: [PATCH 2/2] Launch Namecoin on Windows

---
 src/components/tl-process.js | 17 +++++++++++
 src/modules/tl-util.jsm      | 56 ++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)

diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index 510cbaf..75d8b4e 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -395,6 +395,7 @@ TorProcessService.prototype =
                     TorLauncherUtil.getTorFile("torrc-defaults", false);
       var electrumNMCFile = null;
       var stemNSFile = null;
+      var pythonFile = null;
       var hashedPassword = this.mProtocolSvc.TorGetPassword(true);
       var controlIPCFile = this.mProtocolSvc.TorGetControlIPCFile();
       var controlPort = this.mProtocolSvc.TorGetControlPort();
@@ -415,6 +416,8 @@ TorProcessService.prototype =
 
         electrumNMCFile = TorLauncherUtil.getTorFile("electrum-nmc", false);
         stemNSFile = TorLauncherUtil.getTorFile("stemns", false);
+        if (TorLauncherUtil.isWindows)
+          pythonFile = TorLauncherUtil.getTorFile("python", false);
       }
 
       var detailsKey;
@@ -430,6 +433,8 @@ TorProcessService.prototype =
         detailsKey = "electrum_nmc_missing";
       else if (!stemNSFile && enableNamecoin)
         detailsKey = "stemns_missing";
+      else if (!pythonFile && enableNamecoin && TorLauncherUtil.isWindows)
+        detailsKey = "python_missing";
       else if (!hashedPassword)
         detailsKey = "password_hash_missing";
 
@@ -579,6 +584,11 @@ TorProcessService.prototype =
       if (enableNamecoin)
       {
         args = [];
+        if (TorLauncherUtil.isWindows)
+        {
+          args.push(electrumNMCFile.path);
+          electrumNMCFile = pythonFile;
+        }
         args.push("daemon");
         if (verboseNamecoin)
           args.push("-v");
@@ -595,11 +605,18 @@ TorProcessService.prototype =
         p.runwAsync(args, args.length, this, false);
 
         args = [];
+        if (TorLauncherUtil.isWindows)
+        {
+          args.push(stemNSFile.path);
+          stemNSFile = pythonFile;
+        }
 
         p = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
         p.init(stemNSFile);
 
         TorLauncherLogger.log(2, "Starting " + stemNSFile.path);
+        for (var i = 0; i < args.length; ++i)
+          TorLauncherLogger.log(2, "  " + args[i]);
 
         p.runwAsync(args, args.length, this, false);
       }
diff --git a/src/modules/tl-util.jsm b/src/modules/tl-util.jsm
index ad56752..f2971e8 100644
--- a/src/modules/tl-util.jsm
+++ b/src/modules/tl-util.jsm
@@ -554,6 +554,12 @@ let TorLauncherUtil =  // Public
 
     if (!path && !torFile)
     {
+      let env = Cc["@mozilla.org/process/environment;1"]
+                  .getService(Ci.nsIEnvironment);
+      var verboseNamecoin = false;
+      if (env.exists("TOR_VERBOSE_NAMECOIN"))
+        verboseNamecoin = env.get("TOR_VERBOSE_NAMECOIN") == "1";
+
       // No preference and no pre-determined IPC path: use a default path.
       isRelativePath = true;
       if (TLUtilInternal._isUserDataOutsideOfAppDir)
@@ -575,6 +581,14 @@ let TorLauncherUtil =  // Public
             path = "Tor\\onion-auth";
           else if ("pt-profiles-dir" == aTorFileType)
             path = "Tor\\PluggableTransports";
+          else if ("electrum-nmc" == aTorFileType)
+            path = "TorBrowser\\Electrum-NMC\\run_electrum_nmc";
+          else if ("stemns" == aTorFileType)
+            path = "TorBrowser\\StemNS\\poc.py";
+          else if ("python" == aTorFileType && verboseNamecoin)
+            path = "python.exe";
+          else if ("python" == aTorFileType)
+            path = "pythonw.exe";
         }
         else if (this.isMac)
         {
@@ -636,6 +650,14 @@ let TorLauncherUtil =  // Public
           path = "Data\\Tor\\onion-auth";
         else if ("pt-profiles-dir" == aTorFileType)
           path = "Data\\Browser";
+        else if ("electrum-nmc" == aTorFileType)
+          path = "Electrum-NMC\\run_electrum_nmc";
+        else if ("stemns" == aTorFileType)
+          path = "StemNS\\poc.py";
+        else if ("python" == aTorFileType && verboseNamecoin)
+          path = "python.exe";
+        else if ("python" == aTorFileType)
+          path = "pythonw.exe";
         }
       else // Linux, Mac OS and others.
       {
@@ -668,6 +690,40 @@ let TorLauncherUtil =  // Public
 
     try
     {
+      // Python searching is only a thing on Windows
+      if ("python" == aTorFileType)
+      {
+        const kEnvPath = "PATH";
+        var env = Cc["@mozilla.org/process/environment;1"]
+                    .getService(Ci.nsIEnvironment);
+
+        if (!env.exists(kEnvPath))
+          return null;
+        var searchPaths = env.get(kEnvPath).split(";");
+
+        for (var i = 0; i < searchPaths.length; ++i)
+        {
+          torFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
+          try {
+            torFile.initWithPath(searchPaths[i]);
+          }
+          catch (e)
+          {
+            // Passing the empty string to initWithPath causes an error.
+            // searchPaths will end with an empty string if the PATH contains a
+            // trailing semicolon.  Other invalid/weird paths (if present in
+            // PATH) might also cause an error, so we catch them all here in an
+            // attempt to be tolerant.
+            continue;
+          }
+          torFile.append(path);
+          if (torFile.exists())
+            return torFile;
+        }
+
+        return null;
+      }
+
       if (useAppDir)
       {
         torFile = TLUtilInternal._appDir.clone();
-- 
2.20.1

